package org.dreamwork.jasmine2.jxd;

import org.dreamwork.misc.BASE64Zipper;
import org.dreamwork.jasmine2.web.controls.InternalJS;
import org.dreamwork.misc.MimeTypeManager;
import org.dreamwork.util.ResourceUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Field;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2008-12-24
 * Time: 14:31:07
 */
public class InternalResourceServlet extends HttpServlet {
    private long STATIC_LAST_MODIFY = -1L;

    private String[] getResource (String d) throws Exception {
        d = d.replace ('+', ' ');
        BASE64Zipper encoder = new BASE64Zipper ();
        encoder.setEncoding (InternalResourceManager.ENCODING);
        d = encoder.DESDEcode (d);
        return d.split ("\\|");
    }

    protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            Info info = null;
            if (request.getParameter ("res") != null)
                info = processTextUrl (request);
            else if (request.getParameter ("d") != null)
                info = processEncodedURL (request);
            
            if (info == null || info.url == null) {
                response.sendError (HttpServletResponse.SC_NOT_FOUND);
                response.flushBuffer ();
                return;
            }

            response.setContentType (info.contentType);

            InputStream in = info.url.openStream ();
            try {
                byte[] buff = new byte[1024];
                int length;
                while ((length = in.read (buff)) != -1)
                    response.getOutputStream ().write (buff, 0, length);
                response.getOutputStream ().flush ();
            } finally {
                if (in != null) in.close ();
            }
        } catch (Exception e) {
            e.printStackTrace ();
            throw new ServletException (e);
        }
    }

    private Info processEncodedURL (HttpServletRequest request) throws Exception {
        String d = request.getParameter ("d");
        d = d.replace ('+', ' ');
        String[] resource = getResource (d);
        ClassLoader loader = getClassLoader (resource[0]);
        Info info = new Info ();
        info.url = loader.getResource (resource[1]);
        info.contentType = getContentType (resource[1]);
        return info;
    }

    private Info processTextUrl (HttpServletRequest request) {
        String resource = request.getParameter ("res");
        Class cls = InternalJS.class;
        try {
            File phyFile = ResourceUtil.getPhysicalFile (cls);
            ClassLoader loader = getClassLoader (phyFile);
            Field field = cls.getDeclaredField (resource);
            String path = (String) field.get (null);
            Info info = new Info ();
            info.url = loader.getResource (path);
            info.contentType = getContentType (path);
            return info;
        } catch (Exception ex) {
            return null;
        }
    }

    private String getContentType (String path) {
        int pos = path.lastIndexOf ('.');
        String extension = path.substring (pos + 1);
        return MimeTypeManager.getType (extension);
    }

    private ClassLoader getClassLoader (String phyPath) throws MalformedURLException {
        return new URLClassLoader (new URL[]{new File (phyPath).toURI().toURL ()});
    }

    private ClassLoader getClassLoader (File phyPath) throws MalformedURLException {
        return new URLClassLoader (new URL[]{phyPath.toURI().toURL ()});
    }

    private static class Info {
        URL url;
        String contentType;
    }

    @Override
    protected long getLastModified (HttpServletRequest request) {
        if (STATIC_LAST_MODIFY > 0)
            return STATIC_LAST_MODIFY;

        try {
            File file = ResourceUtil.getPhysicalFile (getClass ());
            return STATIC_LAST_MODIFY = file.lastModified ();
        } catch (Exception e) {
            //
            return STATIC_LAST_MODIFY;
        }
    }
}